#pragma once
#include <iostream>
#include <string>
#include "Socket.hpp"
#include <memory>
#include <jsoncpp/json/json.h>
#include <functional>

using namespace SocketModule;

class Request
{
public:
    Request() {}
    Request(int x, int y, char oper)
        : _x(x), _y(y), _oper(oper)
    {
    }

    int X() { return _x; }
    int Y() { return _y; }
    char Oper() { return _oper; }

    // 序列化
    std::string Serialize()
    {
        std::string s;
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;
        Json::FastWriter writer;
        s = writer.write(root);
        return s;
    }

    // 反序列化
    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (ok)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return ok;
    }

    ~Request() {}

private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response() {}
    Response(int result, int code)
        : _result(result), _code(code)
    {
    }

    void SetResult(int res)
    {
        _result = res;
    }

    void SetCode(int code)
    {
        _code = code;
    }

    // 序列化
    std::string Serialize()
    {
        std::string s;
        Json::Value root;
        Json::FastWriter writer;
        root["result"] = _result;
        root["code"] = _code;
        s = writer.write(root);
        return s;
    }

    // 反序列化
    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (ok)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return ok;
    }

    void ShowResult()
    {
        std::cout << "计算结果是: " << _result 
            << "[code:" << _code << "]" << std::endl; 
    }

    ~Response() {}

private:
    int _result;
    int _code;
};

const std::string sep = "\r\n";

using func_t = std::function<Response(Request &req)>;

class Protocol
{
public:
    Protocol() {}
    Protocol(func_t func) : _func(func) {}

    std::string Encode(const std::string jsonstr)
    {
        std::string len = std::to_string(jsonstr.size());
        return len + sep + jsonstr + sep;
    }

    bool Decode(std::string &buff, std::string *package)
    {
        ssize_t pos = buff.find(sep);
        if (pos == std::string::npos)
        {
            return false;
        }
        std::string package_len_str = buff.substr(0, pos);
        int package_len = std::stoi(package_len_str);
        int len = package_len_str.size() + package_len + 2 * sep.size();
        if (buff.size() < len)
        {
            return false;
        }

        *package = buff.substr(pos + sep.size(), package_len);
        buff.erase(0, len);
        return true;
    }

    void GetRequest(std::shared_ptr<Socket> &socket, InetAddr &client)
    {
        std::string buff_queue;
        while (1)
        {
            int n = socket->Recv(&buff_queue);
            if (n > 0)
            {
                // std::cout << "---------------req_buff----------------" << std::endl;
                // std::cout << buff_queue << std::endl;

                std::string json_package;
                // 解析报文, 判断时候包含一个完整的报文
                while(Decode(buff_queue, &json_package))
                {
                    // std::cout << "--------------resp json-----------------" << std::endl;
                    // std::cout << json_package << std::endl;
                    // std::cout << "---------------req_buff----------------" << std::endl;
                    // std::cout << buff_queue << std::endl;
    
                    LOG(LogLevel::DEBUG) << "client: " << client.StringAddr() << " 请求: " << json_package;

                    // 一定是一个完整的报文,进行反序列化
                    Request req;
                    bool ok = req.Deserialize(json_package);
                    if (!ok)
                    {
                        continue;
                    }
                    // 处理req
                    Response resp = _func(req);
                    // 序列化应答
                    std::string json_str = resp.Serialize();
                    // 添加自定义长度
                    std::string json_resp_str = Encode(json_str);
                    // 直接发送
                    socket->Send(json_resp_str);
                }
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "client: " << client.StringAddr() << " quit";
                break;
            }
            else
            {
                LOG(LogLevel::WARNING) << "client: " << client.StringAddr() << " recv error";
                break;
            }
        }
    }

    bool GetResponse(std::shared_ptr<Socket> &client, std::string &resp_buff, Response *resp)
    {
        while (1)
        {
            int n = client->Recv(&resp_buff);
            if (n > 0)
            {
                // std::cout << "---------------resp_buff----------------" << std::endl;
                // std::cout << resp_buff << std::endl;

                std::string json_package;
                bool ret = Decode(resp_buff, &json_package);
                if (!ret)
                {
                    continue;
                }

                // std::cout << "--------------resp json-----------------" << std::endl;
                // std::cout << json_package << std::endl;
                // std::cout << "---------------resp_buff----------------" << std::endl;
                // std::cout << resp_buff << std::endl;

                resp->Deserialize(json_package);
                return true;
            }
            else if (n == 0)
            {
                std::cout << "server quit" << std::endl;
                return false;
            }
            else
            {
                std::cout << "read failed" << std::endl;
                return false;
            }
        }
    }

    std::string BuildRequestString(int x, int y, char oper)
    {
        Request req(x, y, oper);

        std::string jsonstr = req.Serialize();

        // std::cout << "---------------json_str------------" <<std::endl;
        // std::cout << jsonstr << std::endl;

        return Encode(jsonstr);
    }

    ~Protocol() {}

private:
    Request _req;
    Response _resp;
    func_t _func;
};